from django.apps import AppConfig
from django.db.models.signals import post_migrate
"""
这段代码是Django应用程序配置类SubscriptionsConfig的实现，主要用于在应用程序准备就绪时执行一些初始化操作。
"""
class SubscriptionsConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'subscriptions'

    def ready(self):    # ready方法在应用程序加载完成时调用。
        """应用程序准备就绪时的初始化"""
        # 导入信号处理器
        from . import signals

        # 注册post_migrate信号处理器，Django提供的信号，当数据库迁移完成后触发。
        # 将init_subscriptions方法连接到post_migrate信号，确保在每次数据库迁移完成后执行订阅初始化。
        post_migrate.connect(self.init_subscriptions, sender=self)

    def init_subscriptions(self, sender, **kwargs):
        """初始化订阅管理器"""
        try:
            # 表示OPC UA和MQTT订阅的模型
            from .models import OPCUASubscription, MQTTSubscription
            # 异步任务函数，用于同步OPC UA和MQTT订阅。
            from .tasks import sync_opcua_subscription, sync_mqtt_subscription
            import logging

            logger = logging.getLogger(__name__)
            logger.info("开始初始化订阅...")

            # 重新启动所有活跃的OPC UA订阅
            active_opcua = OPCUASubscription.objects.filter(is_active=True)
            for subscription in active_opcua:
                try:
                    """
                    delay 方法的作用
                        代码片段中，sync_opcua_subscription.delay() 使用了 Celery 的 delay 方法。以下是 delay 方法
                    的主要作用:由 Celery worker 异步执行,这使得主程序可以继续执行其他逻辑，而不必等待任务完成.
                        delay 方法使你可以轻松地将任务异步化，提高应用程序的响应速度和并发处理能力。对于需要长时间运行或资源密
                    集型的任务，使用 delay 是一种常见的优化手段。
                    """
                    sync_opcua_subscription.delay(
                        subscription_id=subscription.id,
                        node_id=subscription.node_id,
                        server_url=subscription.data_source.connection_string
                    )
                    logger.info(f"已启动OPC UA订阅 - ID: {subscription.id}")
                except Exception as e:
                    logger.error(f"启动OPC UA订阅失败 - ID: {subscription.id}, 错误: {str(e)}")

            # 重新启动所有活跃的MQTT订阅
            active_mqtt = MQTTSubscription.objects.filter(is_active=True)
            for subscription in active_mqtt:
                try:
                    sync_mqtt_subscription.delay(
                        subscription_id=subscription.id,
                        topic=subscription.topic,
                        broker_url=subscription.data_source.connection_string
                    )
                    logger.info(f"已启动MQTT订阅 - ID: {subscription.id}")
                except Exception as e:
                    logger.error(f"启动MQTT订阅失败 - ID: {subscription.id}, 错误: {str(e)}")

            logger.info("订阅初始化完成")

        except Exception as e:
            logger.error(f"订阅初始化失败: {str(e)}", exc_info=True)


"""
    在数据迁移操作完成后启动所有活动的OPC UA及MQTT订阅的原因，主要与确保系统状态的一致性和可靠性有关。以下
是具体原因：
    1.确保订阅状态与数据库同步：
        a.数据迁移可能会修改数据库结构或内容，例如添加新的订阅、更新现有订阅的状态等。如果在迁移后不重新初始
          化订阅，可能会导致程序运行时使用的是过期或不一致的订阅信息。
        b.通过在迁移完成后立即重启所有活跃的订阅，可以确保订阅管理器中的状态与最新的数据库记录完全一致。
    2.处理迁移期间可能丢失的订阅：
        a.如果在迁移过程中某些订阅被暂停或中断（例如由于服务重启或网络问题），迁移完成后重新启动这些订阅可以
          确保不会遗漏任何重要的数据流。
        b.这种做法可以提高系统的容错能力，确保即使在迁移期间出现问题，订阅也能尽快恢复正常工作。
    3.避免重复订阅和资源浪费：
        a.在程序启动时启动订阅是常见的做法，但如果在迁移过程中有新的订阅被创建或修改，直接在启动时启动可能会
          导致重复订阅或资源浪费。
        b.通过在迁移完成后重新初始化订阅，可以确保每次都是基于最新的数据库状态进行订阅管理，避免不必要的重复
    操作。
    3.增强系统的健壮性：
        a.迁移操作通常涉及对数据库的结构性变更，这可能会对依赖于数据库的应用逻辑产生影响。通过在迁移后立即
        重启订阅，可以确保应用逻辑能够及时响应这些变更，保持系统的健壮性和稳定性。
总结：
    虽然在程序运行时启动订阅是常见做法，但在数据迁移操作完成后启动所有活动的OPC UA及MQTT订阅是为了确保订
    阅状态与最新的数据库记录一致，处理迁移期间可能丢失的订阅，避免重复订阅和资源浪费，并增强系统的健壮性。
    这种设计有助于确保系统在迁移后的稳定性和可靠性。
"""
